Passed
Push — master ( 260b41...8a6043 )
by Jan
01:55 queued 12s
created

FrameReader.ts ➔ nullTerminatedValueFromBuffer   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
1
import { SplitBuffer, } from "./ID3Util"
2
import * as ID3Util from "./ID3Util"
3
4
type DataType = "string" | "number" | "buffer"
5
6
export class FrameReader {
7
    private _encoding: number
8
    private _splitBuffer: SplitBuffer
9
10
    constructor(
11
        buffer: Buffer,
12
        encodingBytePosition?: number,
13
        consumeEncodingByte = true
14
    ) {
15
        if (!buffer || !(buffer instanceof Buffer)) {
16
            buffer = Buffer.alloc(0)
17
        }
18
        if (
19
            encodingBytePosition !== undefined &&
20
            Number.isInteger(encodingBytePosition)
21
        ) {
22
            this._encoding = buffer[encodingBytePosition] ? buffer[encodingBytePosition] : 0x00
23
            if (consumeEncodingByte) {
24
                buffer = encodingBytePosition === 0 ?
25
                    buffer.subarray(1) :
26
                    Buffer.concat([
27
                        buffer.subarray(0, encodingBytePosition),
28
                        buffer.subarray(encodingBytePosition)
29
                    ])
30
            }
31
        } else {
32
            this._encoding = 0x00
33
        }
34
        this._splitBuffer = new SplitBuffer(null, buffer.subarray(0))
35
    }
36
37
    consumeStaticValue(
38
        dataType: 'string',
39
        size?: number | null,
40
        encoding?: number
41
    ): string
42
    consumeStaticValue(
43
        dataType: 'number',
44
        size?: number | null,
45
        encoding?: number
46
    ): number
47
    consumeStaticValue(
48
        dataType: 'buffer',
49
        size?: number | null,
50
        encoding?: number
51
    ): Buffer
52
    consumeStaticValue(
53
    ): Buffer
54
    consumeStaticValue(
55
        dataType: DataType = 'buffer',
56
        size?: number | null,
57
        encoding = this._encoding
58
    ) {
59
        return this._consumeByFunction(
60
            // TODO check if this._splitBuffer.remainder can be null!
61
            // eslint-disable-next-line
62
            () => staticValueFromBuffer(this._splitBuffer.remainder!, size),
63
            dataType,
64
            encoding
65
        )
66
    }
67
68
    consumeNullTerminatedValue(
69
        dataType: 'string',
70
        encoding?: number
71
     ): string
72
     consumeNullTerminatedValue(
73
        dataType: 'number',
74
        encoding?: number
75
     ): number
76
    consumeNullTerminatedValue(
77
        dataType: DataType,
78
        encoding = this._encoding
79
    ) {
80
        return this._consumeByFunction(
81
            () => ID3Util.splitNullTerminatedBuffer(
82
                // TODO check if this._splitBuffer.remainder can be null!
83
                // eslint-disable-next-line
84
                this._splitBuffer.remainder!,
85
                encoding
86
            ),
87
            dataType,
88
            encoding
89
        )
90
    }
91
92
    private _consumeByFunction(
93
        fn: () => SplitBuffer,
94
        dataType: DataType,
95
        encoding: number
96
    ) {
97
        if (
98
            !this._splitBuffer.remainder ||
99
            this._splitBuffer.remainder.length === 0
100
        ) {
101
            return undefined
102
        }
103
        this._splitBuffer = fn()
104
        if (dataType) {
105
            return convertValue(this._splitBuffer.value, dataType, encoding)
106
        }
107
        return this._splitBuffer.value
108
    }
109
}
110
111
function convertValue(
112
    buffer: Buffer | number | string | null,
113
    dataType: DataType,
114
    encoding = 0x00
115
) {
116
    // TODO: Check this behaviour:
117
    // - if 0 or an empty string is given it will return `undefined`
118
    //   I don't think this should behave that way.
119
    //   I would think this test should not exist, the following one
120
    //   !(buffer instanceof Buffer)) should be sufficient and more correct,
121
    //   removing this test would:
122
    //   - return 0 if 0 is given (instead of undefined)
123
    //   - return "" if "" is given (instead of undefined)
124
    //   - return null if null is given (instead of undefined)
125
    if (!buffer) {
126
        return undefined
127
    }
128
    if (!(buffer instanceof Buffer)) {
129
        return buffer
130
    }
131
    if (buffer.length === 0) {
132
        return undefined
133
    }
134
    if (dataType === "number") {
135
        return parseInt(buffer.toString('hex'), 16)
136
    }
137
    if (dataType === "string") {
138
        return ID3Util.bufferToDecodedString(buffer, encoding)
139
    }
140
    return buffer
141
}
142
143
function staticValueFromBuffer(
144
    buffer: Buffer,
145
    size?: number | null
146
): SplitBuffer {
147
    size = size ?? buffer.length
148
    if (buffer.length > size) {
149
        return new SplitBuffer(
150
            buffer.subarray(0, size), buffer.subarray(size)
151
        )
152
    }
153
    return new SplitBuffer(buffer.subarray(0), null)
154
}
155